import {
    GraphQLSchema,
    isInterfaceType,
    isObjectType,
    isUnionType,
} from 'graphql'
import { excludedTypes } from '../common/excludedTypes'
import { RenderContext } from '../common/RenderContext'

const renderTypeGuard = (target: string, possible: string[]) => {
    return `
    const ${target}_possibleTypes: string[] = [${possible
        .map((t) => `'${t}'`)
        .join(',')}]
    export const is${target} = (obj?: { __typename?: any } | null): obj is ${target} => {
      if (!obj?.__typename) throw new Error('__typename is missing in "is${target}"')
      return ${target}_possibleTypes.includes(obj.__typename)
    }
    `
}

export const renderTypeGuards = (schema: GraphQLSchema, ctx: RenderContext) => {
    const typeMap = schema.getTypeMap()
    for (const name in typeMap) {
        if (excludedTypes.includes(name)) continue

        const type = typeMap[name]

        if (isUnionType(type)) {
            const types = type.getTypes().map((t) => t.name)
            ctx.addCodeBlock(renderTypeGuard(type.name, types))
        } else if (isInterfaceType(type)) {
            const types = schema.getPossibleTypes(type).map((t) => t.name)
            ctx.addCodeBlock(renderTypeGuard(type.name, types))
        } else if (isObjectType(type)) {
            ctx.addCodeBlock(renderTypeGuard(type.name, [type.name]))
        }
    }
}
